
#include "BuiltinShaders.h"

#include <System/Diagnostics/Debug.h>

using namespace Riccsson::System::Diagnostics;

GLuint loadShader(GLenum shaderType, const char* pSource)
{
	GLuint shader = glCreateShader(shaderType);
	if (shader)
	{
		glShaderSource(shader, 1, &pSource, NULL);
		glCompileShader(shader);
		GLint compiled = 0;
		glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
		if (!compiled)
		{
			GLint infoLen = 0;
			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
			if (infoLen)
			{
				char* buf = (char*) malloc(infoLen);
				if (buf)
				{
					glGetShaderInfoLog(shader, infoLen, NULL, buf);
					Debug::WriteLine( "OpenGLES: Could not compile shader." );
					free(buf);
				}
				glDeleteShader(shader);
				shader = 0;
			}
		}
	}
	return shader;
}

GLuint createProgram(const char* pVertexSource, const char* pFragmentSource)
{
	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
	if (!vertexShader)
	{
		return 0;
	}

	GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
	if (!pixelShader)
	{
		return 0;
	}

	GLuint program = glCreateProgram();
	if (program)
	{
		glAttachShader(program, vertexShader);
		//checkGlError("glAttachShader");
		glAttachShader(program, pixelShader);
		//checkGlError("glAttachShader");
		glLinkProgram(program);
		GLint linkStatus = GL_FALSE;
		glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
		if (linkStatus != GL_TRUE)
		{
			GLint bufLength = 0;
			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
			if (bufLength)
			{
				char* buf = (char*) malloc(bufLength);
				if (buf)
				{
					glGetProgramInfoLog(program, bufLength, NULL, buf);
					Debug::WriteLine( "OpenGLES: Could not link program." );
					free(buf);
				}
			}
			Debug::WriteLine( "OpenGLES: Could not link program. glDeleteProgram..." );
			glDeleteProgram(program);
			program = 0;
		}
	}
	return program;
}

static const char gVertexShader[] =
"attribute vec4 a_position;			\n"
"attribute vec2 a_texCoord;			\n"
"attribute vec4 a_v4FillColor;		\n"
"varying vec4 v_v4FillColor;		\n"
"varying vec2 v_texCoord;			\n"
"void main()						\n"
"{									\n"
"	v_v4FillColor = a_v4FillColor;	\n"
"   gl_Position = a_position;		\n"
"   v_texCoord = a_texCoord;		\n"
"}									\n";

static const char gFragmentShader_additive[] =
"precision mediump float;																\n"
"varying vec4 v_v4FillColor;															\n"
"varying vec2 v_texCoord;																\n"
"uniform sampler2D s_texture;															\n"
"void main()																			\n"
"{																						\n"
"	vec4 color = texture2D( s_texture, v_texCoord ) * v_v4FillColor;					\n"
"	float black = color.r + color.g + color.b * 0.33;									\n"
"	color.a = black * color.a;															\n"
"	gl_FragColor = color;																\n"
"}																						\n";

static const char gFragmentShader_opacity[] =
"precision mediump float;																\n"
"varying vec4 v_v4FillColor;															\n"
"varying vec2 v_texCoord;																\n"
"uniform sampler2D s_texture;															\n"
"void main()																			\n"
"{																						\n"
"	gl_FragColor = texture2D( s_texture, v_texCoord ) * v_v4FillColor;					\n"
"}																						\n";

GLuint g_spritebatch_additive_program;
GLuint g_spritebatch_additive_gvPositionHandle;
GLuint g_spritebatch_additive_iLocFillColor;
GLuint g_spritebatch_additive_gvTexture;
GLuint g_spritebatch_additive_texCoordSlot;

GLuint g_spritebatch_opacity_program;
GLuint g_spritebatch_opacity_gvPositionHandle;
GLuint g_spritebatch_opacity_iLocFillColor;
GLuint g_spritebatch_opacity_gvTexture;
GLuint g_spritebatch_opacity_texCoordSlot;